#ifndef _H_C_COROUTINE_H_
#define _H_C_COROUTINE_H_

#include "../typedefine.h"
#include "../threadpool.h"
#include "../collection.h"
#include "../promise.h"
#include <memory>
#include <functional>
#include <atomic>

namespace TB
{
	class CCoroutineImpl;
	class CCoroutineGroup;
	class CCoroutineGroupImpl;
	class ICoroutineUserData;

	class CCoroutine
	{
		NON_COPYABLE(CCoroutine)
		NON_MOVEABLE(CCoroutine)
	public:
		friend class CRunner;
		friend class CPoller;
		friend class CCoroutineGroup;
		inline static std::shared_ptr<CCoroutine> GetCurrent() { return m_poCurrent; }
	public:
		~CCoroutine();
		inline void SetUserData(const std::weak_ptr<ICoroutineUserData>& poUserData) { m_poUserData = poUserData; }
		inline std::weak_ptr<ICoroutineUserData>& GetUserData() { return m_poUserData; }
		inline const std::weak_ptr<ICoroutineUserData>& GetUserData() const { return m_poUserData; }
		inline CTimerMgr& GetTimerMgr() { return *m_poTimerMgr; }
		inline const CTimerMgr& GetTimerMgr() const { return *m_poTimerMgr; }
		inline CCoroutineGroup* GetGroup() { return m_poGroup; }
		inline const CCoroutineGroup* GetGroup() const { return m_poGroup; }
		inline void Post(const std::function<void()>& rcbFunction)
		{
			_Post(&rcbFunction);
		}
		inline void Post()
		{
			_Post(nullptr);
		}
		UINT64 GetID() const;
		const std::weak_ptr<CThreadPool>& GetThreadPool() const;
		std::weak_ptr<CThreadPool>& GetThreadPool();

	private:
		CCoroutine(bool bManualPoll);
		CCoroutine(const std::weak_ptr<CThreadPool>& poThreadPool);
		CCoroutine(CCoroutineGroup* poGroup, const std::weak_ptr<CCoroutineGroupImpl>& poGroupImpl, const std::weak_ptr<CThreadPool>& poThreadPool, bool bManualPoll);
		void Init(const std::weak_ptr<CCoroutine>& poSelf);

	private:
		static void _SetCurrent(const std::shared_ptr<CCoroutine>& poCurrent) { m_poCurrent = poCurrent; }
		void _Post(const std::function<void()>* pcbFunction);

	private:
		thread_local static std::shared_ptr<CCoroutine> m_poCurrent;
	private:
		std::shared_ptr<CCoroutineImpl> m_poImpl;
		CTimerMgr* m_poTimerMgr;
		CCoroutineGroup* m_poGroup = nullptr;
		std::weak_ptr<ICoroutineUserData> m_poUserData;
	};
}

#endif
